#include "ConfigReader.h"
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

ConfigReader::ConfigReader()
{
	// TODO
}

ConfigReader::~ConfigReader()
{
	// TODO
}
string ConfigReader::getIpAddr(int nodeId)
{
	string line;
	ifstream fileStream(ROUTER_PORT_FILE, ifstream::in);
	size_t ipStartPos, ipEndPos;
	size_t idStartPos, idEndPos;
	string ipAddr;
	string nodeIdStr;
	bool idFound = false;
	int nodIdInt;

	if(fileStream.is_open())
	{
		while(fileStream.good())
		{
			getline(fileStream, line);
			idStartPos = line.find("(");
			if(idStartPos != string::npos)
			{
				idStartPos++;
				idEndPos = line.find(",");
				if(idEndPos != string::npos)
				{
					nodeIdStr = line.substr(idStartPos, idEndPos-idStartPos);
					istringstream convert(nodeIdStr);
					if ( (convert >> nodIdInt) )
					{
						if(nodIdInt == nodeId)
						{
							idFound = true;
							break;
						}
					}

				}
			}
		}
	}
	if(idFound == true)
	{
		ipStartPos = line.find(",");
		if(ipStartPos != string::npos)
		{
			ipStartPos++;
			ipEndPos = line.rfind(",");
			if(idEndPos != string::npos)
			{
				ipAddr = line.substr(ipStartPos, ipEndPos-ipStartPos);
			}
			else
			{
				cout<<"Unable to parse the IP address file properly."<<endl;
				return NULL;
			}
		}
		else
		{
			cout<<"Unable to parse the IP address file properly."<<endl;
			return NULL;
		}
	}
	else
	{
		cout<<"Unable to find the router ID in the IP address file properly."<<endl;
		return NULL;
	}
	return ipAddr;
}

int ConfigReader::getPortNum(int nodeId)
{
	string line;
	ifstream fileStream(ROUTER_PORT_FILE, ifstream::in);
	size_t portStartPos, portEndPos;
	size_t idStartPos, idEndPos;
	string strPort;
	string nodeIdStr;
	int nPort;
	bool idFound = false;
	int nodIdInt;

	if(fileStream.is_open())
	{
		while(fileStream.good())
		{
			getline(fileStream, line);
			idStartPos = line.find("(");
			if(idStartPos != string::npos)
			{
				idStartPos++;
				idEndPos = line.find(",");
				if(idEndPos != string::npos)
				{
					nodeIdStr = line.substr(idStartPos, idEndPos-idStartPos);
					istringstream convert(nodeIdStr);
					if ( (convert >> nodIdInt) )
					{
						if(nodIdInt == nodeId)
						{
							idFound = true;
							break;
						}
					}

				}
			}
		}
	}
	else
	{
		cout<<"Unable to open the IP address file"<<endl;
		return false;
	}
	if(idFound == true)
	{
		portStartPos = line.rfind(",");
		if(portStartPos != string::npos)
		{
			portStartPos++;
			portEndPos = line.find(")");
			if(idEndPos != string::npos)
			{
				strPort = line.substr(portStartPos, portEndPos-portStartPos);
				istringstream convert(strPort);
				if ( !(convert >> nPort) )
				{
					cout<<"Unable to parse the port number properly."<<endl;
					return 0;
				}
			}
			else
			{
				cout<<"Unable to parse the port number properly."<<endl;
				return 0;
			}
		}
		else
		{
			cout<<"Unable to parse the port number file properly."<<endl;
			return 0;
		}
	}
	else
	{
		cout<<"Unable to find the router ID in the IP address file properly."<<endl;
		return 0;
	}
	return nPort;
}
bool ConfigReader::extractNodeInfo(char *nodeInfoStr, NODE_INFO &nodeInfo )
{
	char nodeId[10];
	char portNum[10];
	char gatewayStatus[10];
	char *tempStr;
	tempStr = strtok(nodeInfoStr, ",");
	strcpy(nodeId,tempStr);
	tempStr = strtok(NULL, ",");
	strcpy(portNum,tempStr);
	tempStr = strtok(NULL, ",");
	strcpy(gatewayStatus,tempStr);
	nodeInfo.nNodeID = atoi(nodeId);
	nodeInfo.strIP = getIpAddr(nodeInfo.nNodeID);
	nodeInfo.nPort = getPortNum(nodeInfo.nNodeID);
	if(strcmp(gatewayStatus, "g") == 0)
	{
		nodeInfo.bGateway = true;
	}
	else
	{
		nodeInfo.bGateway = false;
	}

	return true;
}
bool ConfigReader::extractNeighborInfo(char * nodeInfoStr, NEIGBOUR_INFO &neigbInfo)
{
	char nodeId[10];
	char portNum[10];
	char gatewayStatus[10];
	char *tempStr;
	tempStr = strtok(nodeInfoStr, ",");
	strcpy(nodeId,tempStr);
	tempStr = strtok(NULL, ",");
	strcpy(portNum,tempStr);
	tempStr = strtok(NULL, ",");
	strcpy(gatewayStatus,tempStr);
	neigbInfo.nNodeID = atoi(nodeId);
	neigbInfo.strIP = getIpAddr(neigbInfo.nNodeID);
	neigbInfo.nPort = getPortNum(neigbInfo.nNodeID);
	if(strcmp(gatewayStatus, "g") == 0)
	{
		neigbInfo.bGateway = true;
	}
	else
	{
		neigbInfo.bGateway = false;
	}
	return true;
}
bool ConfigReader::Initialize(NODE_INFO &nodeInfo, vector<NEIGBOUR_INFO> &vecNeigbInfo, int nodeId)
{
	string nodeIdStr;
	bool idFound = false;
	int nodIdInt;
	string line;
	ifstream fileStream(CONFIG_FILE, ifstream::in);
	size_t idStartPos, idEndPos;
	char *tempStr;
	char nodeInfoStr[10][30];
	int index = 0;
	int numOfNeighbors = 0;
	if(fileStream.is_open())
	{
		while(fileStream.good())
		{
			getline(fileStream, line);
			idStartPos = line.find("(");
			if(idStartPos != string::npos)
			{
				idStartPos++;
				idEndPos = line.find(",");
				if(idEndPos != string::npos)
				{
					nodeIdStr = line.substr(idStartPos, idEndPos-idStartPos);
					istringstream convert(nodeIdStr);
					if ( (convert >> nodIdInt) )
					{
						if(nodIdInt == nodeId)
						{
							idFound = true;
							break;
						}
					}

				}
			}
		}
		if(idFound == false)
		{
			cout<<"Unable to find the node ID."<<endl;
			exit(0);
			return false;
		}
		tempStr = strtok((char*)line.c_str(), "() ");
		while (tempStr != NULL)
		{
			strcpy(nodeInfoStr[index++], tempStr);
			tempStr = strtok(NULL, "() ");
		}
		numOfNeighbors = index-1;
		nodeInfo.nNeighbCount = numOfNeighbors;
		if(!(extractNodeInfo(nodeInfoStr[0], nodeInfo)))
		{
			cout<<"Error in extracting the node information"<<endl;
			exit(0);
			return false;
		}
		for(index = 0; index < numOfNeighbors; index++ )
		{
			NEIGBOUR_INFO temp;
			vecNeigbInfo.push_back(temp);
			if(!(extractNeighborInfo(nodeInfoStr[index+1],vecNeigbInfo[index])))
			{
				cout<<"Error in extracting the neighbour node information"<<endl;
				exit(0);
				return false;
			}
			if(vecNeigbInfo[index].bGateway == true)
			{
				nodeInfo.nGatewayID = vecNeigbInfo[index].nNodeID;
			}
		}
		if(nodeInfo.bGateway == true)
		{
			nodeInfo.nGatewayID = nodeInfo.nNodeID;
		}
	}
	else
	{
		cout<<"Unable to open the configuration file"<<endl;
		exit(0);
		return false;
	}
	return true;
}

